package com.siyoumi.app.sys.service;

import com.siyoumi.app.sys.service.impl.WxTokenServiceImpl;
import com.siyoumi.app.sys.service.impl.WxTokenServiceWxOpenClientImpl;
import com.siyoumi.app.sys.service.impl.WxTokenServiceWxOpenMasterImpl;
import com.siyoumi.component.XRedis;
import com.siyoumi.component.XRedisLock;
import com.siyoumi.entity.SysAccsuperConfig;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.exception.XException;
import com.siyoumi.service.SysAccsuperConfigService;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import com.siyoumi.validator.XValidator;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

//微信token
@Slf4j
public abstract class WxTokenService {
    @Setter
    @Getter
    private SysAccsuperConfig entityConfig;

    public static WxTokenService getBean(SysAccsuperConfig entityConfig) {
        WxTokenService wxToken = null;
        if (entityConfig.wxOpen()) {
            if (XStr.isNullOrEmpty(entityConfig.getAconfig_wxopen_parent())) {
                //主站点
                wxToken = new WxTokenServiceWxOpenMasterImpl();
            } else {
                //授权站点
                wxToken = new WxTokenServiceWxOpenClientImpl();
            }
        }

        if (wxToken == null) {
            wxToken = new WxTokenServiceImpl();
        }

        wxToken.setEntityConfig(entityConfig);
        return wxToken;
    }

    private String getRedisKeyAccessToken(String x) {
        return XStr.concat("cache_model:SysAccsuperConfig|", x, "|access_token");
    }

    /**
     * redis key js_ticket
     */
    private String getRedisKeyJsTicket(String x) {
        return XStr.concat("cache_model:SysAccsuperConfig|", x, "|js_ticket");
    }

    public String getAccessToken() {
        SysAccsuperConfig entityConfig = getEntityConfig();
        if (!entityConfig.wxOpen()) {
            if (XStr.isNullOrEmpty(entityConfig.getAconfig_app_id()) || XStr.isNullOrEmpty(entityConfig.getAconfig_app_secret())) {
                log.error("{}: 未配置app_id或者app_secret", entityConfig.getAconfig_id());
                throw new XException(EnumSys.API_ERROR.getR(entityConfig.getAconfig_id() + "：未配置app_id或者app_secret"));
            }
        }

        SysAccsuperConfigService app = SysAccsuperConfigService.getBean();
        XRedis redis = XRedis.getBean();

        String redisKey = getRedisKeyAccessToken(entityConfig.getKey());
        String accessToken = redis.get(redisKey);
        if (XStr.hasAnyText(accessToken)) {
            log.info("cacheKey: {}", redisKey);
            log.info("access_token cache");
            return accessToken;
        }

        log.info("加锁，准备更新access_token");
        String lockKey = XStr.concat(redisKey, "|lock");
        XReturn rToken = XRedisLock.lockFunc(lockKey, k -> {
            XReturn r = XReturn.getR(0);
            String accessTokenNew = redis.get(redisKey);
            if (XStr.hasAnyText(accessTokenNew)) {
                log.info("并发操作，已更新过");
                r.setData("accessToken", accessTokenNew);
                return r;
            }

            SysAccsuperConfig entityConfigUpdate = new SysAccsuperConfig();
            entityConfigUpdate.setAconfig_id(entityConfig.getAconfig_id());

            accessTokenNew = getApiToken(entityConfig);

            entityConfigUpdate.setAconfig_access_token(accessTokenNew);

            if (entityConfig.wx()) {
                log.info("公众号需要更新js_ticket");
                String jsApiTicketNew = getApiJsTicket(entityConfig);
                entityConfigUpdate.setAconfig_js_ticket(jsApiTicketNew);

                log.info("js_ticket重新设置缓存");
                redis.setEx(getRedisKeyJsTicket(entityConfig.getKey()), jsApiTicketNew, 3600);
            }
            app.saveOrUpdatePassEqualField(entityConfig, entityConfigUpdate);

            log.info("access_token重新设置缓存");
            redis.setEx(redisKey, accessTokenNew, 3600);


            r.setData("accessToken", accessTokenNew);
            return r;
        }, -1);
        if (rToken.err()) {
            XValidator.err(rToken);
        }
        accessToken = rToken.getData("accessToken");


        return accessToken;
    }

    public String getJsTicket() {
        SysAccsuperConfig entityConfig = getEntityConfig();
        if (!entityConfig.wx()) {
            //只有公众号有js_ticket
            return null;
        }

        XRedis redis = XRedis.getBean();

        String redisKey = getRedisKeyJsTicket(entityConfig.getKey());
        String jsTicket = redis.get(redisKey);
        if (XStr.hasAnyText(jsTicket)) {
            log.info("cacheKey: {}", redisKey);
            log.info("js_ticket cache");
            return jsTicket;
        }

        getAccessToken();

        return redis.get(redisKey);
    }

    abstract protected String getApiToken(SysAccsuperConfig entityConfig);

    abstract protected String getApiJsTicket(SysAccsuperConfig entityConfig);
}
